package com.xiaoshuidi.cloud.module.contract.service.contract.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.common.util.json.JsonUtils;
import com.xiaoshuidi.cloud.framework.redis.sequence.TimebaseSequenceGenerator;
import com.xiaoshuidi.cloud.framework.tenant.core.util.TenantUtils;
import com.xiaoshuidi.cloud.module.bpm.api.task.BpmProcessInstanceApi;
import com.xiaoshuidi.cloud.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import com.xiaoshuidi.cloud.module.bpm.enums.BpmBusinessTypeEnum;
import com.xiaoshuidi.cloud.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.xiaoshuidi.cloud.module.bpm.mq.message.BpmProcessInstanceResultEvent;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.HomeQueryVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.RoomContractRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ownerContract.*;
import com.xiaoshuidi.cloud.module.contract.controller.app.contract.vo.OwnerHouseInfoRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.app.contract.vo.OwnerHouseRentInfoRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.app.contract.vo.OwnerHouseRoomQueryReqVO;
import com.xiaoshuidi.cloud.module.contract.convert.contract.ContractHouseOwnerConvert;
import com.xiaoshuidi.cloud.module.contract.convert.contract.ContractHouseOwnerRoomRefConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.RentOrderDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.*;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.roommeta.ContractRoommateDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractHouseOwnerMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractHouseOwnerPropertyMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractHouseOwnerPropertyTemplateMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractHouseOwnerRoomRefMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.ApproveTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderPayStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.*;
import com.xiaoshuidi.cloud.module.contract.service.approval.ContractApprovalService;
import com.xiaoshuidi.cloud.module.contract.service.bill.OwnerOrderService;
import com.xiaoshuidi.cloud.module.contract.service.bill.dto.RentOrderCreateDTO;
import com.xiaoshuidi.cloud.module.contract.service.bill.dto.RentOrderQueryDTO;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractHouseOwnerService;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractRoomService;
import com.xiaoshuidi.cloud.module.contract.service.contract.dto.*;
import com.xiaoshuidi.cloud.module.contract.service.roommate.ContractRoommateService;
import com.xiaoshuidi.cloud.module.contract.util.date.DateUtils;
import com.xiaoshuidi.cloud.module.contract.vo.ApproveReqVO;
import com.xiaoshuidi.cloud.module.member.api.user.MemberUserApi;
import com.xiaoshuidi.cloud.module.member.api.user.dto.MemberUserReqDTO;
import com.xiaoshuidi.cloud.module.member.api.user.dto.MemberUserRespDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomhouse.RoomHouseApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomhouse.vo.FreezeRepairReqVO;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.RoomStateRecordApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.vo.GetCurrentRecordRespVO;
import com.xiaoshuidi.cloud.module.rooms.enums.RentStatusEnum;
import com.xiaoshuidi.cloud.module.rooms.vo.RoomHouseRespVo;
import com.xiaoshuidi.cloud.module.system.api.user.AdminUserApi;
import com.xiaoshuidi.cloud.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.xiaoshuidi.cloud.module.contract.enums.ApiConstants.*;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.*;

/**
 * 业主合同 Service 实现类
 *
 * @author 合房租赁
 */
@Slf4j
@Service
public class ContractHouseOwnerServiceImpl implements ContractHouseOwnerService {

    @Resource
    private ContractHouseOwnerMapper houseOwnerMapper;
    @Resource
    private ContractHouseOwnerRoomRefMapper contractHouseOwnerRoomRefMapper;
    @Resource
    private RoomHouseApi roomHouseApi;
    @Resource
    private RoomStateRecordApi roomStateRecordApi;
    @Lazy
    @Resource
    private OwnerOrderService ownerOrderService;
    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private ContractRoomService contractRoomService;
    @Resource
    private ContractRoommateService contractRoommateService;
    @Resource
    private ContractApprovalService contractApprovalService;
    @Resource
    private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Value("${spring.application.name}")
    private String applicationName;
    @Resource
    private TimebaseSequenceGenerator timebaseSequenceGenerator;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private ContractHouseOwnerPropertyTemplateMapper ownerPropertyTemplateMapper;
    @Resource
    private ContractHouseOwnerPropertyMapper ownerPropertyMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createHouseOwner(ContractHouseOwnerCreateReqVO createReq) {
        String contractNode;
        if (Objects.isNull(createReq.getOriginalContractId())){
            // 无原合同编号 新签合同
            // 判断关联房间是否已关联其他业主合同
            validateHouseOwnerRoomExists(createReq.getRefRoom());
            contractNode = ContractNodeEnum.NEW.getCode();
        }else {
            contractNode = ContractNodeEnum.RENEWAL.getCode();
            // 续租合同校验参数
            validateRenewalContractParam(createReq);
        }
        // 押金默认值0
        if (Objects.isNull(createReq.getDeposit())){
            createReq.setDeposit(BigDecimal.ZERO);
        }
        // 插入关联房间
        ContractHouseOwnerRoomRefDO ownerContractRefRoom = buildOwnerRoomRefAndInsert(createReq.getRefRoom());
        // 插入业主合同
        ContractHouseOwnerDO houseOwner = buildContractOwnerAndInsert(createReq, ownerContractRefRoom, contractNode);
        ownerContractRefRoom.setContractHouseOwnerId(houseOwner.getId());
        contractHouseOwnerRoomRefMapper.insert(ownerContractRefRoom);
        // 插入业主资产信息
        saveOwnerAssetInfo(createReq, houseOwner.getId());
        //  插入账单信息
        buildRentOrder(createReq, ownerContractRefRoom, houseOwner.getId());
        // 续租的合同已生效 原合同押金结转
        if (ContractNodeEnum.RENEWAL.getCode().equals(contractNode)){
            // 续租审批
            String processDefinitionKey = contractApprovalService.getByRoomIdAndMark(createReq.getRefRoom().getApartmentId(), ApproveTypeEnum.RENEWAL_OWNER_CONTRACT.getMsg());
            if (StringUtils.isNotBlank(processDefinitionKey)) {
                String processInstanceId = createRenewalProcessInstance(houseOwner, createReq.getRefRoom(), processDefinitionKey);
                houseOwner.setProcessInstanceId(processInstanceId);
                houseOwner.setContractStatus(ContractOwnerStatusEnum.PENDING.getCode());
                houseOwnerMapper.updateById(houseOwner);
            }
            // 押金结转
            ownerOrderService.handleRenewalOrder(houseOwner.getOriginalContractId());
            // 续租合同已生效处理
            if (ContractOwnerStatusEnum.ACTIVE.getCode().equals(houseOwner.getContractStatus()) && StringUtils.isBlank(processDefinitionKey)){
                ContractHouseOwnerDO originalHouseOwner = new ContractHouseOwnerDO();
                originalHouseOwner.setId(houseOwner.getOriginalContractId());
                originalHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
                // 更新原合同
                houseOwnerMapper.updateById(originalHouseOwner);
            }
        }

        return houseOwner.getId();
    }

    // 插入业主资产信息
    private void saveOwnerAssetInfo(ContractHouseOwnerCreateReqVO createReq, Long ownerContractId){
        List<ContractHouseOwnerPropertyDO> propertyListAll = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(createReq.getPropertyList())) {
            List<ContractHouseOwnerPropertyDO> propertyList = createReq.getPropertyList();
            propertyList.forEach(p -> {
                p.setType(0);
                p.setId(null);
            });
            propertyListAll.addAll(propertyList);
        }
        if (CollectionUtil.isNotEmpty(createReq.getFurnitureList())) {
            List<ContractHouseOwnerPropertyDO> furnitureList = createReq.getFurnitureList();
            furnitureList.forEach(f -> {
                f.setType(1);
                f.setId(null);
            });
            propertyListAll.addAll(furnitureList);
        }
        if (CollectionUtils.isNotEmpty(propertyListAll)) {
            propertyListAll.forEach(p -> p.setHouseOwnerId(ownerContractId));
            ownerPropertyMapper.insertBatch(propertyListAll);
        }
    }

    private void validateRenewalContractParam(ContractHouseOwnerCreateReqVO createReq){
        // 原合同信息
        ContractHouseOwnerDO contractHouseOwnerDO = houseOwnerMapper.selectById(createReq.getOriginalContractId());
        if (Objects.isNull(contractHouseOwnerDO)){
            throw exception(HOUSE_OWNER_NOT_EXISTS);
        }
        // 租期开始时间校验 原合同结束时间+1天
        LocalDate startTime = contractHouseOwnerDO.getEndTime().plusDays(ONE);
        if (!startTime.equals(createReq.getStartTime())){
            throw exception(RENEWAL_OWNER_CONTRACT_START_TIME_NOT_MODIFIABLE);
        }
//        // 押金 不可修改
//        if (contractHouseOwnerDO.getDeposit().compareTo(createReq.getDeposit()) != ZERO){
//            throw exception(RENEWAL_OWNER_CONTRACT_DEPOSIT_NOT_MODIFIABLE);
//        }
        // 续租根合同ID
        if (Objects.nonNull(contractHouseOwnerDO.getRootId())){
            createReq.setRootId(contractHouseOwnerDO.getRootId());
        }else {
            createReq.setRootId(contractHouseOwnerDO.getId());
        }
        // 校验原合同账单已支付
        checkRenewal(contractHouseOwnerDO.getId());
        // 原合同账单已支付 押金需要结转
        createReq.setCarryForwardDeposit(contractHouseOwnerDO.getDeposit());
    }

    private ContractHouseOwnerDO buildContractOwnerAndInsert(ContractHouseOwnerCreateReqVO createReq,ContractHouseOwnerRoomRefDO contractHouseOwnerRoomRefDO, String contractNode){
        // 插入
        ContractHouseOwnerDO houseOwner = ContractHouseOwnerConvert.INSTANCE.convert(createReq);
        houseOwner.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
        houseOwner.setContractNode(contractNode);
        houseOwner.setSignedTime(LocalDateTime.now());
        houseOwner.setApproveStatus(ContractApproveEnum.NO_AUDIT_REQUITED.getCode());
        houseOwner.setSignStatus(ContractSignStatusEnum.SIGNED.getCode());
        if (ContractTypeEnum.ELECTRONIC.getCode().equals(houseOwner.getContractType())){
            houseOwner.setSignStatus(ContractSignStatusEnum.SIGNED_PARTY_A.getCode());
            houseOwner.setContractStatus(ContractOwnerStatusEnum.NO_SIGNED.getCode());
        }
        //默认 提前收租
        houseOwner.setRentPayWay(ContractRentCollectionTypeEnum.ADVANCED.getCode());
        LocalDate nowDate = LocalDate.now();
        // 续租
        if (ContractNodeEnum.RENEWAL.getCode().equals(contractNode)
                && ContractTypeEnum.PAPER.getCode().equals(createReq.getContractType())
                && houseOwner.getStartTime().isAfter(nowDate)){
            houseOwner.setContractStatus(ContractOwnerStatusEnum.WAITING_ACTIVE.getCode());
        }
        // 业主会员编号获取
        Long ownerMemberId = getOwnerMemberId(houseOwner);
        if (Objects.isNull(ownerMemberId)){
            throw exception(GET_OWNER_MEMBER_NUMBER_FAILED);
        }
        houseOwner.setMemberId(ownerMemberId);
        //生成电子合同编号
        String contractNum = CONTRACT_OWNER_PREFIX + timebaseSequenceGenerator.YYYYMMDD.next("lease:contractOwner:number");
        houseOwner.setContractNo(contractNum);
        houseOwnerMapper.insert(houseOwner);
        if (ContractNodeEnum.NEW.getCode().equals(contractNode)){
            // 新签审批
            String processDefinitionKey = contractApprovalService.getByRoomIdAndMark(contractHouseOwnerRoomRefDO.getApartmentId(), ApproveTypeEnum.OWNER_CONTRACT.getMsg());
            if (StringUtils.isNotBlank(processDefinitionKey)) {
                String processInstanceId = createProcessInstance(houseOwner, createReq.getRefRoom(), processDefinitionKey);
                houseOwner.setProcessInstanceId(processInstanceId);
                houseOwner.setContractStatus(ContractOwnerStatusEnum.PENDING.getCode());
                houseOwnerMapper.updateById(houseOwner);
            }
        }
        return houseOwner;
    }

    private String createProcessInstance(ContractHouseOwnerDO contractHouseOwnerDO, ContractOwnerRoomRefVO roomRef, String processDefinitionId) {
        // 工作流参数
        BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
        bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(processDefinitionId);
        bpmProcessInstanceCreateReqDTO.setBusinessType(BpmBusinessTypeEnum.OWNER_CONTRACT.name());
        bpmProcessInstanceCreateReqDTO.setBusinessKey(String.valueOf(contractHouseOwnerDO.getId()));
        Map<String, Object> variables = new HashMap<>();
        variables.put("customerName", contractHouseOwnerDO.getOwnerName());
        variables.put("customerPhone", contractHouseOwnerDO.getPhone());
        variables.put("roomName", roomRef.getRoomName());
        variables.put("roomId", roomRef.getRoomId());
        variables.put("createName", Objects.nonNull(getLoginUser())?getLoginUser().getNickname():"");
        variables.put("contractStartDate", contractHouseOwnerDO.getStartTime().format(DateTimeFormatter.ISO_DATE));
        variables.put("contractEndDate", contractHouseOwnerDO.getEndTime().format(DateTimeFormatter.ISO_DATE));
        bpmProcessInstanceCreateReqDTO.setVariables(variables);
        bpmProcessInstanceCreateReqDTO.setTenantId(Objects.nonNull(getLoginUser())?getLoginUser().getTenantId():null);
        bpmProcessInstanceCreateReqDTO.setServiceName(applicationName);
        BpmProcessInstanceCreateReqDTO.ExtendDto extendDto = new BpmProcessInstanceCreateReqDTO.ExtendDto();
        extendDto.setRoomId(Objects.nonNull(roomRef.getRoomId())?roomRef.getRoomId().toString():"");
        extendDto.setContractId(null);
        extendDto.setContractNo(contractHouseOwnerDO.getContractNo());
        extendDto.setOwnerContractId(contractHouseOwnerDO.getId());
        extendDto.setRoomName(roomRef.getRoomName());
        extendDto.setApartmentId(roomRef.getApartmentId());
        extendDto.setApartmentName(null);
        extendDto.setCustomName(contractHouseOwnerDO.getOwnerName());
        extendDto.setCustomPhone(contractHouseOwnerDO.getPhone());
        bpmProcessInstanceCreateReqDTO.setExtendDto(extendDto);
        CommonResult<String> processInstance = bpmProcessInstanceApi.createProcessInstance(getLoginUserId(), bpmProcessInstanceCreateReqDTO);
        log.info("processInstance:{}", JsonUtils.toJsonString(processInstance));
        return processInstance.getCheckedData();
    }

    private String createRenewalProcessInstance(ContractHouseOwnerDO contractHouseOwnerDO, ContractOwnerRoomRefVO roomRef, String processDefinitionId){
        // 原合同信息
        ContractHouseOwnerDO oldOwnerContract = this.validateHouseOwnerExists(contractHouseOwnerDO.getOriginalContractId());
        //  账单信息
        RentOrderQueryDTO queryDTO = new RentOrderQueryDTO();
        queryDTO.setOrderType(OrderTypeEnum.OWNER.getCode());
        queryDTO.setBusinessId(contractHouseOwnerDO.getId());
        List<RentOrderDO> rentOrderList = ownerOrderService.getListByParam(queryDTO);

        // 工作流参数
        BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
        bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(processDefinitionId);
        bpmProcessInstanceCreateReqDTO.setBusinessType(BpmBusinessTypeEnum.HOUSE_OWNER_RENEWAL.name());
        bpmProcessInstanceCreateReqDTO.setBusinessKey(String.valueOf(contractHouseOwnerDO.getId()));
        Map<String, Object> variables = new HashMap<>();
        variables.put("createName", Objects.nonNull(getLoginUser())?getLoginUser().getNickname():"");
        variables.put("createId", Objects.nonNull(getLoginUser())?getLoginUser().getId():null);
        variables.put("roomName", roomRef.getRoomName());
        variables.put("roomId", roomRef.getRoomId());
        variables.put("roomAddress", roomRef.getRoomAddress());
        variables.put("ownerContractInfo", ContractHouseOwnerConvert.INSTANCE.convertDo2BpmDto(contractHouseOwnerDO));
        variables.put("oldOwnerContractInfo", ContractHouseOwnerConvert.INSTANCE.convertDo2BpmDto(oldOwnerContract));
        variables.put("rentOrderList", ContractHouseOwnerConvert.INSTANCE.convertRentOrders2BpmDtos(rentOrderList));
        bpmProcessInstanceCreateReqDTO.setVariables(variables);
        bpmProcessInstanceCreateReqDTO.setTenantId(Objects.nonNull(getLoginUser())?getLoginUser().getTenantId():null);
        bpmProcessInstanceCreateReqDTO.setServiceName(applicationName);
        BpmProcessInstanceCreateReqDTO.ExtendDto extendDto = new BpmProcessInstanceCreateReqDTO.ExtendDto();
        extendDto.setRoomId(Objects.nonNull(roomRef.getRoomId())?roomRef.getRoomId().toString():"");
        extendDto.setContractId(null);
        extendDto.setContractNo(contractHouseOwnerDO.getContractNo());
        extendDto.setOwnerContractId(contractHouseOwnerDO.getId());
        extendDto.setRoomName(roomRef.getRoomName());
        extendDto.setApartmentId(roomRef.getApartmentId());
        extendDto.setApartmentName(null);
        extendDto.setCustomName(contractHouseOwnerDO.getOwnerName());
        extendDto.setCustomPhone(contractHouseOwnerDO.getPhone());
        bpmProcessInstanceCreateReqDTO.setExtendDto(extendDto);
        CommonResult<String> processInstance = bpmProcessInstanceApi.createProcessInstance(getLoginUserId(), bpmProcessInstanceCreateReqDTO);
        log.info("processInstance:{}", JsonUtils.toJsonString(processInstance));
        return processInstance.getCheckedData();
    }

    /**
     * 获取业主会员编号
     */
    private Long getOwnerMemberId(ContractHouseOwnerDO houseOwner) {
        MemberUserReqDTO reqDTO = new MemberUserReqDTO();
        reqDTO.setMobile(houseOwner.getPhone());
        reqDTO.setName(houseOwner.getOwnerName());
        reqDTO.setCardNo(houseOwner.getIdNumber());
        CommonResult<MemberUserRespDTO> userInfo = memberUserApi.getUserInfo(reqDTO);
        log.info("新增业主合同，获取会员信息，请求参数：{}，返回参数：{}", JSONObject.toJSONString(reqDTO), Objects.nonNull(userInfo)?JSONObject.toJSONString(reqDTO):"");
        userInfo.checkError();
        MemberUserRespDTO data = userInfo.getData();
        if (Objects.nonNull(data)){
            return data.getId();
        }
        return null;
    }

    private ContractHouseOwnerRoomRefDO buildOwnerRoomRefAndInsert(ContractOwnerRoomRefVO refRoom){
        // 插入关联房间
        ContractHouseOwnerRoomRefDO ownerContractRefRoom = ContractHouseOwnerRoomRefConvert.INSTANCE.convertRoomRefVO2RoomRefDO(refRoom);
        if (Objects.isNull(refRoom.getRoomId())){
            throw exception(OWNER_CONTRACT_NOT_REF_ROOM);
        }
        CommonResult<RoomHouseRespVo> roomHouseInfoById = roomHouseApi.getRoomHouseinfoById(refRoom.getRoomId());
        log.info("创建业主合同，请求房源查询房间信息，参数：{}，返回参数：{}", refRoom.getRoomId(), roomHouseInfoById);
        if (Objects.isNull(roomHouseInfoById) || Objects.isNull(roomHouseInfoById.getData())){
            throw exception(ROOM_NOT_EXIST);
        }
        RoomHouseRespDTO roomHouseRespDTO = ContractHouseOwnerRoomRefConvert.INSTANCE.converRespVo2RespDto(roomHouseInfoById.getData());
        ownerContractRefRoom.setApartmentId(roomHouseRespDTO.getApartmentId());
        ownerContractRefRoom.setApartmentName(roomHouseRespDTO.getApartmentName());
        return ownerContractRefRoom;
    }
    
    /**
     * 创建业主账单
     */
    private void buildRentOrder(ContractHouseOwnerCreateReqVO createReqVO, ContractHouseOwnerRoomRefDO ownerContractRefRoom, Long ownerContractId){
        //组装生成账单的数据
        OwnerContractRentOrderDTO rentOrder = OwnerContractRentOrderDTO.builder()
                .businessId(ownerContractId)
                .apartmentId(ownerContractRefRoom.getApartmentId())
                .apartmentName(ownerContractRefRoom.getApartmentName())
                .roomId(ownerContractRefRoom.getRoomId())
                .roomName(ownerContractRefRoom.getRoomName())
                .startTime(createReqVO.getStartTime())
                .endTime(createReqVO.getEndTime())
                .monthRent(createReqVO.getMonthRent())
                .depositAmount(createReqVO.getDeposit())
                .oldDepositAmount(createReqVO.getDeposit())
                .month(createReqVO.getPayMethodF())
                .orderType(OrderTypeEnum.OWNER.getCode())
                .rentPayWay(ContractRentCollectionTypeEnum.ADVANCED.getCode())
                .advancedDays(createReqVO.getAdvancedDays())
                .rentFreePeriod(createReqVO.getRentFreePeriod())
                .originalContractId(createReqVO.getOriginalContractId())
                .carryForwardDeposit(createReqVO.getCarryForwardDeposit())
                .build();
        //生成账单
        ownerOrderService.ownerContractCreateRentOrder(rentOrder);
    }

    private void validateHouseOwnerRoomExists(ContractOwnerRoomRefVO refRoom) {
        List<String> statusList = Arrays.asList(ContractOwnerStatusEnum.PENDING.getCode(), ContractOwnerStatusEnum.NO_SIGNED.getCode(),
                ContractOwnerStatusEnum.WAITING_ACTIVE.getCode(), ContractOwnerStatusEnum.ACTIVE.getCode(),ContractOwnerStatusEnum.REJECT.getCode());
        List<ContractHouseOwnerDO> renewalOwnerContractList = houseOwnerMapper.getRenewalOwnerContractList(refRoom.getRoomId(), null, statusList);
        if (CollectionUtils.isNotEmpty(renewalOwnerContractList)){
            throw exception(ROOM_ALREADY_REF_OTHER_OWNER_CONTRACT);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateHouseOwner(ContractHouseOwnerUpdateReqVO updateReqVO) {
        // 校验存在
        ContractHouseOwnerDO contractHouseOwnerDO = validateHouseOwnerExists(updateReqVO.getId());
        // 仅已驳回 可编辑修改业主合同
        if (!ContractOwnerStatusEnum.REJECT.getCode().equals(contractHouseOwnerDO.getContractStatus())){
            throw exception(OWNER_STATUS_UNABLE_TO_OPERATE);
        }
        if (CollectionUtils.isEmpty(updateReqVO.getContractAnnexUrls())){
            updateReqVO.setContractAnnexUrls(null);
        }
        if (CollectionUtils.isEmpty(updateReqVO.getDocumentAnnexUrls())){
            updateReqVO.setDocumentAnnexUrls(null);
        }

        // 审批驳回后重新编辑 再次发起审批
        //查询关联房间信息
        ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(updateReqVO.getId());
        if (Objects.isNull(contractRefRoom)){
            throw exception(HOUSE_OWNER_CONTRACT_REF_ROOM_NOT_FOUND);
        }
        // 合同关联房间信息更新
        if (contractRefRoom.getRoomId().longValue() != updateReqVO.getRefRoom().getRoomId().longValue()){
            // 判断关联房间是否已关联其他业主合同
            validateHouseOwnerRoomExists(updateReqVO.getRefRoom());
            // 删除原关联房间信息
            contractHouseOwnerRoomRefMapper.deleteById(contractRefRoom.getId());
            // 保存编辑后的关联房间
            contractRefRoom = buildOwnerRoomRefAndInsert(updateReqVO.getRefRoom());
            contractRefRoom.setContractHouseOwnerId(updateReqVO.getId());
            contractHouseOwnerRoomRefMapper.insert(contractRefRoom);
        }
        // 更新合同信息
        ContractHouseOwnerDO updateHouseOwner = buildContractOwnerAndUpdate(updateReqVO, contractRefRoom, contractHouseOwnerDO.getContractNode());

        // 删除原业主账单信息
        ownerOrderService.deleteOrderByBusinessId(updateReqVO.getId(), OrderTypeEnum.OWNER.getCode());
        //  插入新的账单信息
        ContractHouseOwnerCreateReqVO buildRentOrderVO = new ContractHouseOwnerCreateReqVO();
        buildRentOrderVO.setStartTime(updateReqVO.getStartTime());
        buildRentOrderVO.setEndTime(updateReqVO.getEndTime());
        buildRentOrderVO.setMonthRent(updateReqVO.getMonthRent());
        buildRentOrderVO.setDeposit(updateReqVO.getDeposit());
        buildRentOrderVO.setPayMethodF(updateReqVO.getPayMethodF());
        buildRentOrderVO.setAdvancedDays(updateReqVO.getAdvancedDays());
        buildRentOrderVO.setRentFreePeriod(updateReqVO.getRentFreePeriod());
        buildRentOrderVO.setOriginalContractId(contractHouseOwnerDO.getOriginalContractId());
        buildRentOrderVO.setStartTime(updateReqVO.getStartTime());
        if (ContractNodeEnum.RENEWAL.getCode().equals(contractHouseOwnerDO.getContractNode())){
            // 续租合同校验
            validateRenewalContractParam(buildRentOrderVO);
        }
        buildRentOrder(buildRentOrderVO, contractRefRoom, updateReqVO.getId());
        // 续租的合同已生效 原合同押金结转
        if (ContractNodeEnum.RENEWAL.getCode().equals(updateHouseOwner.getContractNode())){
            // 续租审批
            String processDefinitionKey = contractApprovalService.getByRoomIdAndMark(updateReqVO.getRefRoom().getApartmentId(), ApproveTypeEnum.RENEWAL_OWNER_CONTRACT.getMsg());
            if (StringUtils.isNotBlank(processDefinitionKey)) {
                //记录审批
                contractHouseOwnerDO.setDeposit(updateHouseOwner.getDeposit());
                contractHouseOwnerDO.setMonthRent(updateHouseOwner.getMonthRent());
                contractHouseOwnerDO.setPayMethodF(updateHouseOwner.getPayMethodF());
                contractHouseOwnerDO.setUpdateTime(LocalDateTime.now());
                String processInstanceId = createRenewalProcessInstance(contractHouseOwnerDO,
                        updateReqVO.getRefRoom(), processDefinitionKey);
                updateHouseOwner.setProcessInstanceId(processInstanceId);
                updateHouseOwner.setContractStatus(ContractOwnerStatusEnum.PENDING.getCode());
                houseOwnerMapper.updateById(updateHouseOwner);
            }

//            // 押金结转
//            ownerOrderService.handleRenewalOrder(contractHouseOwnerDO.getOriginalContractId());
            if (ContractOwnerStatusEnum.ACTIVE.getCode().equals(updateHouseOwner.getContractStatus())){
                if (StringUtils.isBlank(processDefinitionKey)){
                    ContractHouseOwnerDO originalHouseOwner = new ContractHouseOwnerDO();
                    originalHouseOwner.setId(contractHouseOwnerDO.getOriginalContractId());
                    originalHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
                    // 更新原合同
                    houseOwnerMapper.updateById(originalHouseOwner);
                }
            }
        }

    }

    private ContractHouseOwnerDO buildContractOwnerAndUpdate(ContractHouseOwnerUpdateReqVO updateReqVO,ContractHouseOwnerRoomRefDO contractHouseOwnerRoomRefDO, String contractNode){
        // 插入
        ContractHouseOwnerDO houseOwner = ContractHouseOwnerConvert.INSTANCE.convert(updateReqVO);
        houseOwner.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
        houseOwner.setContractNode(contractNode);
        houseOwner.setSignedTime(LocalDateTime.now());
        houseOwner.setApproveStatus(ContractApproveEnum.NO_AUDIT_REQUITED.getCode());
        houseOwner.setSignStatus(ContractSignStatusEnum.SIGNED.getCode());
        if (ContractTypeEnum.ELECTRONIC.getCode().equals(houseOwner.getContractType())){
            houseOwner.setSignStatus(ContractSignStatusEnum.SIGNED_PARTY_A.getCode());
            houseOwner.setContractStatus(ContractOwnerStatusEnum.NO_SIGNED.getCode());
        }
        //默认 提前收租
        houseOwner.setRentPayWay(ContractRentCollectionTypeEnum.ADVANCED.getCode());
        LocalDate nowDate = LocalDate.now();
        // 续租 纸质 未开始  合同状态为待生效
        if (ContractNodeEnum.RENEWAL.getCode().equals(contractNode)
                && ContractTypeEnum.PAPER.getCode().equals(updateReqVO.getContractType())
                && houseOwner.getStartTime().isAfter(nowDate)){
            houseOwner.setContractStatus(ContractOwnerStatusEnum.WAITING_ACTIVE.getCode());
        }
        if (StringUtils.isNotBlank(updateReqVO.getPhone()) && StringUtils.isNotBlank(updateReqVO.getOwnerName())
                && StringUtils.isNotBlank(updateReqVO.getIdNumber())){
            // 业主会员ID
            Long ownerMemberId = getOwnerMemberId(houseOwner);
            if (Objects.isNull(ownerMemberId)){
                throw exception(GET_OWNER_MEMBER_NUMBER_FAILED);
            }
            houseOwner.setMemberId(ownerMemberId);
        }
        if (ContractNodeEnum.NEW.getCode().equals(contractNode)){
            // 新签审批
            String processDefinitionKey = contractApprovalService.getByRoomIdAndMark(contractHouseOwnerRoomRefDO.getApartmentId(), ApproveTypeEnum.OWNER_CONTRACT.getMsg());
            if (StringUtils.isNotBlank(processDefinitionKey)) {
                String processInstanceId = createProcessInstance(houseOwner, updateReqVO.getRefRoom(), processDefinitionKey);
                houseOwner.setProcessInstanceId(processInstanceId);
                houseOwner.setContractStatus(ContractOwnerStatusEnum.PENDING.getCode());
            }
        }
        houseOwnerMapper.updateById(houseOwner);

        houseOwnerMapper.updateById(houseOwner);

        // 业主资产信息修改
        if (CollectionUtils.isNotEmpty(updateReqVO.getFurnitureList()) || CollectionUtils.isNotEmpty(updateReqVO.getPropertyList())){
            // 先删除原数据
            LambdaQueryWrapper<ContractHouseOwnerPropertyDO> deleteWrapper = new LambdaQueryWrapper<>();
            deleteWrapper.eq(ContractHouseOwnerPropertyDO::getHouseOwnerId, updateReqVO.getId());
            ownerPropertyMapper.delete(deleteWrapper);
            List<ContractHouseOwnerPropertyDO> ownerAssetList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(updateReqVO.getFurnitureList())){
                // 新增修改后的资产信息
                List<ContractHouseOwnerPropertyDO> furnitureList = updateReqVO.getFurnitureList();
                furnitureList.forEach(f -> {f.setType(1); f.setId(null);});
                ownerAssetList.addAll(furnitureList);
            }
            if (CollectionUtils.isNotEmpty(updateReqVO.getPropertyList())){
                List<ContractHouseOwnerPropertyDO> propertyList = updateReqVO.getPropertyList();
                propertyList.forEach(p -> {p.setType(0); p.setId(null);});
                ownerAssetList.addAll(propertyList);
            }
            ownerAssetList.forEach(a -> {a.setId(null); a.setHouseOwnerId(houseOwner.getId());});
            ownerPropertyMapper.insertBatch(ownerAssetList);
        }
        return houseOwner;
    }

    @Override
    public void deleteHouseOwner(Long id, Boolean deleteBill) {
        // 校验存在
        validateHouseOwnerExists(id);
        // 删除关联房间
        LambdaQueryWrapper<ContractHouseOwnerRoomRefDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId, id);
        contractHouseOwnerRoomRefMapper.delete(queryWrapper);

        // 删除
        houseOwnerMapper.deleteById(id);

        // 删除资产信息
        LambdaQueryWrapper<ContractHouseOwnerPropertyDO> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(ContractHouseOwnerPropertyDO::getHouseOwnerId, id);
        ownerPropertyMapper.delete(deleteWrapper);

        if (deleteBill){
            // 同时删除已确认账单和流水
            // 删除业主续租合同账单及账单明细
            ownerOrderService.deleteOrderByBusinessId(id, OrderTypeEnum.OWNER.getCode());
        }
    }

    private ContractHouseOwnerDO validateHouseOwnerExists(Long id) {
        ContractHouseOwnerDO contractHouseOwner = houseOwnerMapper.selectById(id);
        if (contractHouseOwner == null) {
            throw exception(HOUSE_OWNER_NOT_EXISTS);
        }
        return contractHouseOwner;
    }


    @Override
    public ContractHouseOwnerRespVO getHouseOwnerResp(Long id) {
        ContractHouseOwnerDO contractHouseOwner = houseOwnerMapper.selectById(id);
        ContractHouseOwnerRespVO resp = ContractHouseOwnerConvert.INSTANCE.convert(contractHouseOwner);
        if (Objects.nonNull(contractHouseOwner)){
            //查询关联房间信息
            ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(id);
            if (Objects.nonNull(contractRefRoom)){
                resp.setRefRoom(ContractHouseOwnerRoomRefConvert.INSTANCE.convertRoomRefDO2RoomRefVO(contractRefRoom));
            }
        }
        // 合同页面展示状态
        // 待审批、待签约（平台待签约）、待签约（业主待签约）、待生效、已生效、已退租、已取消、已到期
        ContractOwnerShowStatusEnum statusEnum = explainStatus(contractHouseOwner.getContractStatus(), contractHouseOwner.getContractNode(), contractHouseOwner.getEndTime(),
                contractHouseOwner.getSignStatus(), contractHouseOwner.getApproveStatus());
        if (Objects.nonNull(statusEnum)){
            String contractStatusName = statusEnum.getMsg();
            String contractShowStatus = statusEnum.getCode();
            if (ContractOwnerShowStatusEnum.NO_SIGNED.getCode().equals(statusEnum.getCode())){
                if (ContractSignStatusEnum.SIGNED_PARTY_A.getCode().equals(contractHouseOwner.getSignStatus())){
                    contractStatusName = ContractOwnerShowStatusEnum.PLATFORM_NO_SIGNED.getMsg();
                    contractShowStatus = ContractOwnerShowStatusEnum.PLATFORM_NO_SIGNED.getCode();
                }else if (ContractSignStatusEnum.SIGNED_PARTY_B.getCode().equals(contractHouseOwner.getSignStatus())){
                    contractStatusName = ContractOwnerShowStatusEnum.OWNER_NO_SIGNED.getMsg();
                    contractShowStatus = ContractOwnerShowStatusEnum.OWNER_NO_SIGNED.getCode();
                }
            }
            resp.setContractStatusName(contractStatusName);
            resp.setContractShowStatus(contractShowStatus);
        }
        if (Objects.nonNull(contractHouseOwner.getCreator())){
            try {
                CommonResult<AdminUserRespDTO> user = adminUserApi.getUser(Long.valueOf(contractHouseOwner.getCreator()));
                user.checkError();
                String nickname = user.getData().getNickname();
                resp.setPromoterName(nickname);
            } catch (Exception e) {
                log.error("业主合同详情，查询用户信息失败，用户编号：{}", contractHouseOwner.getCreator());
            }
        }

        // 业主资产信息
        List<ContractHouseOwnerPropertyDO> ownerPropertyDOS = ownerPropertyMapper.selectList(ContractHouseOwnerPropertyDO::getHouseOwnerId, id);
        Map<Integer, List<ContractHouseOwnerPropertyDO>> collect = ownerPropertyDOS.stream().collect(Collectors.groupingBy(ContractHouseOwnerPropertyDO::getType));
        resp.setPropertyList(collect.get(0));
        resp.setFurnitureList(collect.get(1));
        return resp;
    }

    private ContractHouseOwnerRoomRefDO getContractRefRoom(Long contractId){
        LambdaQueryWrapper<ContractHouseOwnerRoomRefDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId, contractId);
        queryWrapper.orderByDesc(ContractHouseOwnerRoomRefDO::getCreateTime);
        List<ContractHouseOwnerRoomRefDO> contractHouseOwnerRoomRefList = contractHouseOwnerRoomRefMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractHouseOwnerRoomRefList)){
            return contractHouseOwnerRoomRefList.get(ZERO);
        }
        return null;
    }

    @Override
    public ContractHouseOwnerDO getHouseOwner(Long id) {
        return houseOwnerMapper.selectById(id);
    }


    @Override
    public PageResult<ContractHouseOwnerPageRespVO> getHouseOwnerPage(ContractHouseOwnerPageReqVO pageReqVO) {
        Page<ContractHouseOwnerPageRespVO> page = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize());
        IPage<ContractHouseOwnerPageRespVO> contractHouseOwnerPageRespPage = houseOwnerMapper.pageContractHouseOwnerList(page, pageReqVO);
        List<ContractHouseOwnerPageRespVO> records = buildOwnerRespList(contractHouseOwnerPageRespPage.getRecords());
        return new PageResult<>(records,  contractHouseOwnerPageRespPage.getTotal());
    }

    private List<ContractHouseOwnerPageRespVO> buildOwnerRespList(List<ContractHouseOwnerPageRespVO> records){
        if (CollectionUtils.isNotEmpty(records)){
            List<Long> hosueIds =
                    records.stream().filter(f -> ObjectUtil.isNotNull(f.getHouseRoomId())).map(ContractHouseOwnerPageRespVO::getHouseRoomId).collect(Collectors.toList());
            CommonResult<List<RoomHouseRespVo>> roomHouseAndLayoutByIds =
                    roomHouseApi.getRoomHouseAndLayoutByIds(hosueIds);
            List<RoomHouseRespVo> respVoList = null;
            if (roomHouseAndLayoutByIds.isSuccess() && Objects.nonNull(roomHouseAndLayoutByIds.getData())){
                respVoList = roomHouseAndLayoutByIds.getData();
            }
            for (ContractHouseOwnerPageRespVO record : records) {
                if (Objects.nonNull(record.getStartTime()) && Objects.nonNull(record.getEndTime())){
                    //合同周期
                    String startTimeStr = record.getStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_DATE));
                    String endTimeStr = record.getEndTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_DATE));
                    record.setContractPeriod(startTimeStr + ApiConstants.WAVY_LINE + endTimeStr);
                    //租期
                    String leaseTerm = DateUtils.calculateTimeBetweenStr(record.getStartTime(), record.getEndTime());
                    record.setLeaseTerm(leaseTerm);
                }
                if (Objects.nonNull(record.getPayMethodF()) && Objects.nonNull(record.getMonthRent()) && Objects.nonNull(record.getDeposit())){
                    //付款方式
                    String payMethodStr = toPayMethodStr(record.getPayMethodF(), record.getMonthRent(), record.getDeposit());
                    record.setPayMethodFStr(payMethodStr);
                }
                if (StringUtils.isNotBlank(record.getContractStatus()) && StringUtils.isNotBlank(record.getContractNode())){
                    // 状态
                    ContractOwnerShowStatusEnum statusEnum = explainStatus(record.getContractStatus(),record.getContractNode(),record.getEndTime(), record.getSignStatus(),record.getApproveStatus());
                    if (Objects.nonNull(statusEnum)){
                        record.setStatusStr(statusEnum.getMsg());
                        record.setStatusCode(statusEnum.getCode());
                        String contractShowStatus = statusEnum.getCode();
                        if (ContractOwnerShowStatusEnum.NO_SIGNED.getCode().equals(statusEnum.getCode())){
                            if (ContractSignStatusEnum.SIGNED_PARTY_A.getCode().equals(record.getSignStatus())){
                                contractShowStatus = ContractOwnerShowStatusEnum.PLATFORM_NO_SIGNED.getCode();
                            }else if (ContractSignStatusEnum.SIGNED_PARTY_B.getCode().equals(record.getSignStatus())){
                                contractShowStatus = ContractOwnerShowStatusEnum.OWNER_NO_SIGNED.getCode();
                            }
                        }
                        record.setContractShowStatus(contractShowStatus);
                    }
                }
                //来源： 新签 续租
                if (StringUtils.isNotBlank(record.getContractNode())){
                    record.setContractNode(ContractNodeEnum.getEnum(record.getContractNode()).getMsg());

                }

                if (Objects.nonNull(record.getHouseRoomId())&&CollectionUtil.isNotEmpty(respVoList)){
                    respVoList.stream().filter(f->f.getId().compareTo(record.getHouseRoomId())==0).findFirst().ifPresent(p->{
                        record.setRoomHouseTypeName(p.getRoomHouseTypeName());
                        record.setDistrict(p.getDistrict());
                        record.setWholeTypeName(p.getIsWhole()?"整租":"合租");
                        record.setSpace(p.getSpace());
                    });
                }
            }
        }
        return records;
    }

    private ContractOwnerShowStatusEnum explainStatus(String contractStatus, String contractNode, LocalDate endTime, String signStatus, String approveStatus){
        // 状态  待审批、待签约、待生效(续租待生效)、已生效、已到期、已退租、已取消
        ContractOwnerShowStatusEnum status = null;
        if (ContractOwnerStatusEnum.WAITING_ACTIVE.getCode().equals(contractStatus)
                && ContractNodeEnum.RENEWAL.getCode().equals(contractNode)){
            // 待生效
            // 合同状态待生效 节点续约
            status = ContractOwnerShowStatusEnum.WAITING_ACTIVE;
        }
        if (Objects.nonNull(endTime) && endTime.isBefore(LocalDate.now())
                && ContractOwnerStatusEnum.ACTIVE.getCode().equals(contractStatus)){
            // 已到期
            // 结束时间在当前时间之前  合同状态已生效
            status = ContractOwnerShowStatusEnum.EXPIRED;
        }
        if (ContractOwnerStatusEnum.NORMAL_END.getCode().equals(contractStatus)
                && !ContractNodeEnum.RENTING_OUT.getCode().equals(contractNode)){
            // 已结束
            // 结束时间在当前时间之前  合同状态已生效
            status = ContractOwnerShowStatusEnum.ENDED;
        }
        if (ContractNodeEnum.RENTING_OUT.getCode().equals(contractNode)
                && ContractOwnerStatusEnum.NORMAL_END.getCode().equals(contractStatus)){
            // 已退租
            // 合同节点退租 状态正常结束
            status = ContractOwnerShowStatusEnum.RENTING_OUT;
        }
        if (ContractOwnerStatusEnum.CANCELED.getCode().equals(contractStatus)){
            // 已取消
            // 合同状态已取消
            status = ContractOwnerShowStatusEnum.CANCELED;
        }
        if (ContractOwnerStatusEnum.ACTIVE.getCode().equals(contractStatus) &&
                Objects.nonNull(endTime) && (LocalDate.now().isBefore(endTime) || LocalDate.now().equals(endTime))){
            // 已生效
            // 合同状态已生效 结束时间在当前时间后
            status = ContractOwnerShowStatusEnum.ACTIVE;
        }
        if (ContractOwnerStatusEnum.NO_SIGNED.getCode().equals(contractStatus)
                && !ContractSignStatusEnum.SIGNED.getCode().equals(signStatus) ){
            // 待签约
            // 合同状态待签约 在线签约状态非已签约
            status = ContractOwnerShowStatusEnum.NO_SIGNED;
        }
        if (ContractOwnerStatusEnum.PENDING.getCode().equals(contractStatus)) {
            status = ContractOwnerShowStatusEnum.PENDING_APPROVAL;
        }
        if (ContractOwnerStatusEnum.REJECT.getCode().equals(contractStatus)) {
            status = ContractOwnerShowStatusEnum.REJECT;
        }
        return status;
    }


    private static String toPayMethodStr(Integer payMethod, BigDecimal monthRent, BigDecimal deposit){
        StringBuilder stringBuilder = new StringBuilder();
        try {
            stringBuilder.append(PAY_STR);
            String numberChinese = Convert.numberToChinese(payMethod, false);
            // 数字转中文 十位数问题 11 ==》 一十一
            if (payMethod / TEN == ONE){
                numberChinese = numberChinese.substring(ONE);
            }
            stringBuilder.append(numberChinese);
            stringBuilder.append(DEPOSIT_STR);
            if (monthRent.compareTo(BigDecimal.ZERO) == 0){
                stringBuilder.append(OTHER_STR);
            }else {
                // 除法的同时求余数
                BigDecimal[] dr = deposit.divideAndRemainder(monthRent);
                if (dr[1].signum() == 0){
                    //可以整除
                    String depositStr = Convert.numberToChinese(dr[0].longValue(), false);
                    stringBuilder.append(depositStr);
                }else {
                    stringBuilder.append(OTHER_STR);
                }
            }
        } catch (Exception e) {
            log.error("押几付几计算异常：押{}，月租金{}，押金{}", payMethod,monthRent,deposit);
        }
        return stringBuilder.toString();
    }


    @Override
    public List<ContractHouseOwnerPageRespVO> getExportHouseOwnerList(ContractHouseOwnerPageReqVO pageVO) {
        return buildOwnerRespList(houseOwnerMapper.pageContractHouseOwnerList(pageVO));
    }

    @Override
    public ContractHouseOwnerRespVO getRenewalContract(Long id) {
        // 查询原始合同
        ContractHouseOwnerRespVO houseOwnerResp = getHouseOwnerResp(id);
        // 校验是否已存在续租合同
        validateOwnerRenewalContract(id);

        houseOwnerResp.setOriginalContractId(houseOwnerResp.getId());
        houseOwnerResp.setId(null);
        houseOwnerResp.setCreateTime(null);
        houseOwnerResp.setContractNo(null);
        houseOwnerResp.setApproveStatus(null);
        houseOwnerResp.setContractStatus(null);
        houseOwnerResp.setContractNode(ContractNodeEnum.RENEWAL.getCode());
        houseOwnerResp.setSignedTime(null);
        //续租 开始时间为上个合同结束时间+1天且无法编辑
        houseOwnerResp.setStartTime(houseOwnerResp.getEndTime().plusDays(ONE));
        houseOwnerResp.setEndTime(null);

        // 业主资产信息
        List<ContractHouseOwnerPropertyDO> ownerPropertyDOS = ownerPropertyMapper.selectList(ContractHouseOwnerPropertyDO::getHouseOwnerId, id);
        Map<Integer, List<ContractHouseOwnerPropertyDO>> collect = ownerPropertyDOS.stream().collect(Collectors.groupingBy(ContractHouseOwnerPropertyDO::getType));
        houseOwnerResp.setPropertyList(collect.get(0));
        houseOwnerResp.setFurnitureList(collect.get(1));
        ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(id);
        //物品或者家电资产存在为空
        if(CollectionUtils.isEmpty(houseOwnerResp.getPropertyList()) || CollectionUtils.isEmpty(houseOwnerResp.getFurnitureList())){
            List<ContractHouseOwnerPropertyTemplateDO> dos =
                    ownerPropertyTemplateList(contractRefRoom.getApartmentId());
            //物品为空
            if(CollectionUtils.isEmpty(houseOwnerResp.getPropertyList())){
                List<ContractHouseOwnerPropertyDO> collect1 =
                        dos.stream().filter(f -> f.getType() == 0).map(p->{
                            p.setId(null);
                            p.setCreateTime(null);
                            p.setUpdateTime(null);
                            p.setCreator(null);
                            p.setUpdater(null);
                            ContractHouseOwnerPropertyDO propertyDO = new ContractHouseOwnerPropertyDO();
                            BeanUtil.copyProperties(p,propertyDO);
                            propertyDO.setProjectName(p.getName());
                            return propertyDO;
                        }).collect(Collectors.toList());
                houseOwnerResp.setPropertyList(BeanUtil.copyToList(collect1,ContractHouseOwnerPropertyDO.class));
            }
            //家电为空
            if(CollectionUtils.isEmpty(houseOwnerResp.getFurnitureList())){
                List<ContractHouseOwnerPropertyDO> collect1 =
                        dos.stream().filter(f -> f.getType() == 1).map(p->{
                            p.setId(null);
                            p.setCreateTime(null);
                            p.setUpdateTime(null);
                            p.setCreator(null);
                            p.setUpdater(null);
                            ContractHouseOwnerPropertyDO propertyDO = new ContractHouseOwnerPropertyDO();
                            BeanUtil.copyProperties(p,propertyDO);
                            propertyDO.setThingName(p.getName());
                            return propertyDO;
                        }).collect(Collectors.toList());
                houseOwnerResp.setFurnitureList(collect1);
            }
        }

        return houseOwnerResp;
    }

    private ContractHouseOwnerRoomRefDO validateOwnerRefRoom(Long id){
        ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(id);
        if (Objects.isNull(contractRefRoom)){
            throw exception(HOUSE_OWNER_CONTRACT_REF_ROOM_NOT_FOUND);
        }
        return contractRefRoom;
    }

    /**
     * 校验当前合同是否存在有效的续租合同
     */
    private void validateOwnerRenewalContract(Long contractId){
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerDO::getContractNode, ContractNodeEnum.RENEWAL.getCode());
        queryWrapper.eq(ContractHouseOwnerDO::getOriginalContractId, contractId);
        queryWrapper.ne(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.CANCELED.getCode());
        List<ContractHouseOwnerDO> renewalOwnerContractList = houseOwnerMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(renewalOwnerContractList)){
            throw exception(OWNER_RENEWAL_CONTRACT_EXIST);
        }
    }
    @Override
    public void evictionOwnerContract(ContractHouseOwnerCancelReqVO reqVo) {
        // 校验存在
        ContractHouseOwnerDO contractHouseOwner = validateHouseOwnerExists(reqVo.getOwnerContractId());
        if (!ContractOwnerStatusEnum.ACTIVE.getCode().equals(contractHouseOwner.getContractStatus())){
            throw exception(OWNER_STATUS_UNABLE_TO_OPERATE);
        }
        if (Objects.nonNull(contractHouseOwner.getEvictionTime())){
            // 存在退租时间  说明业主合同已经申请了退租
            throw exception(OWNER_EVICTION_CONTRACT_EXIST);
        }
        // 校验业主合同关联房间
        ContractHouseOwnerRoomRefDO ownerRoomRef = validateOwnerRefRoom(reqVo.getOwnerContractId());
        // 校验业主合同是否有续租合同
        validateOwnerRenewalContract(reqVo.getOwnerContractId());

        // 判断当前房间房态 空房、冻结、维修可以退租
        validateRoomStatus(reqVo.getOwnerContractId());

        reqVo.setMonthRent(contractHouseOwner.getMonthRent());
        reqVo.setStartTime(contractHouseOwner.getStartTime());
        reqVo.setEndTime(contractHouseOwner.getEndTime());
        // 数据校验
        validateOwnerEvictionReq(reqVo, contractHouseOwner);
        //审批流
        String mark = contractApprovalService.getByRoomIdAndMark(ownerRoomRef.getApartmentId(),
                ApproveTypeEnum.HOUSE_OWNER_RENTING_OUT.getMsg());
        if (StringUtils.isNotBlank(mark)) {
            //进入审批
            reqVo.setIsBpmApprove(true);
            //创建流程
            contractHouseOwner.setContractStatus(ContractOwnerStatusEnum.PENDING.getCode());
            houseOwnerMapper.updateById(contractHouseOwner);
            //发起审批记录账单
            createProcessInstance(mark, contractHouseOwner
                    , reqVo
                    , getContractRefRoom(contractHouseOwner.getId())
                    , ownerOrderService.ownerWithdrawal(reqVo, ownerRoomRef));
        } else {
            //无审批
            // 更新业主合同信息
            contractHouseOwner.setEvictionReason(reqVo.getEvictionReason());
            contractHouseOwner.setEvictionTime(reqVo.getEvictionTime());
            contractHouseOwner.setEvictionType(reqVo.getCancelType());
            contractHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
            contractHouseOwner.setContractNode(ContractNodeEnum.RENTING_OUT.getCode());
            houseOwnerMapper.updateById(contractHouseOwner);

            // 修改房态为冻结
            FreezeRepairReqVO req = new FreezeRepairReqVO();
            req.setRoomHouseId(ownerRoomRef.getRoomId());
            roomHouseApi.roomFreeze(req);
            // 生成对应账单
            // 业主合同退租账单处理
            ownerOrderService.ownerWithdrawal(reqVo, ownerRoomRef);
        }

    }

    /**
     * 业主退租审批回调
     */
    @Override
    public void approvalResult(BpmProcessInstanceResultEvent event) {
        // 校验存在
        ContractHouseOwnerDO contractHouseOwner = validateHouseOwnerExists(Long.parseLong(event.getBusinessKey()));

        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(event.getResult())) {
            //修改为生效
            CommonResult<Map<String, Object>> processVariablesMap =
                    bpmProcessInstanceApi.getProcessVariablesMap(event.getId());
            //获取流程参数
            if (processVariablesMap.isSuccess() && ObjectUtil.isNotEmpty(processVariablesMap.getData())) {
                Optional.ofNullable(processVariablesMap.getData()).map(m -> m.get("renting_out")).ifPresent(f -> {
                    ContractHouseOwnerCancelReqVO vo =
                            JSONObject.parseObject(JSONObject.toJSONString(f), ContractHouseOwnerCancelReqVO.class);
                    contractHouseOwner.setEvictionReason(vo.getEvictionReason());
                    contractHouseOwner.setEvictionTime(vo.getEvictionTime());
                    contractHouseOwner.setEvictionType(vo.getCancelType());
                    contractHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
                    contractHouseOwner.setContractNode(ContractNodeEnum.RENTING_OUT.getCode());
                    houseOwnerMapper.updateById(contractHouseOwner);
                    //取消原有账单
                    // 未付款账单状态改为取消
                    ownerOrderService.cancelUnpaidOrder(vo);
                    // 修改房态为冻结
                    ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(contractHouseOwner.getId());
                    FreezeRepairReqVO req = new FreezeRepairReqVO();
                    req.setRoomHouseId(contractRefRoom.getRoomId());
                    roomHouseApi.roomFreeze(req);
                });
                Optional.ofNullable(processVariablesMap.getData()).map(m -> m.get("rentOrder_crate")).ifPresent(f -> {
                    RentOrderCreateDTO vo =
                            JSONObject.parseObject(JSONObject.toJSONString(f), RentOrderCreateDTO.class);
                    //生成账单
                    ownerOrderService.createRentOrderAndOrderFees(CollectionUtil.newArrayList(vo), YZHTZD, null);
                });

            }

        } else {
            //拒绝驳回
            contractHouseOwner.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
            //订单审批状态修改为驳回并取消
            houseOwnerMapper.updateById(contractHouseOwner);
        }
    }

    /**
     * 发起审批请求
     */
    private String createProcessInstance(String mark, ContractHouseOwnerDO contractHouseOwner, ContractHouseOwnerCancelReqVO reqVo,
                                         ContractHouseOwnerRoomRefDO contractRefRoom, RentOrderCreateDTO rentOrderCreateDTO) {
        //退租发起人
        reqVo.setOperator(Objects.nonNull(getLoginUser())?getLoginUser().getNickname():"");
        // 工作流参数
        BpmProcessInstanceCreateReqDTO bpmProcessInstanceCreateReqDTO = new BpmProcessInstanceCreateReqDTO();
        bpmProcessInstanceCreateReqDTO.setProcessDefinitionKey(mark);
        bpmProcessInstanceCreateReqDTO.setBusinessType(BpmBusinessTypeEnum.HOUSE_OWNER_RENTING_OUT.name());
        bpmProcessInstanceCreateReqDTO.setBusinessKey(String.valueOf(reqVo.getOwnerContractId()));
        bpmProcessInstanceCreateReqDTO.setTenantId(Objects.nonNull(getLoginUser())?getLoginUser().getTenantId():null);
        bpmProcessInstanceCreateReqDTO.setServiceName(applicationName);
        log.info("processInstance userId {}, request : {}", getLoginUserId(),
                JsonUtils.toJsonString(bpmProcessInstanceCreateReqDTO));
        HashMap<String, Object> map = MapUtil.of("createName", Objects.nonNull(getLoginUser())?getLoginUser().getNickname():"");
        map.put("renting_out", reqVo);
        map.put("rentOrder_crate", rentOrderCreateDTO);
        map.put("contract_house_owner", contractHouseOwner);
        map.put("contract_ref_room", contractRefRoom);
        //写入临时的
        bpmProcessInstanceCreateReqDTO.setVariables(map);
        BpmProcessInstanceCreateReqDTO.ExtendDto extendDto = new BpmProcessInstanceCreateReqDTO.ExtendDto();
        extendDto.setRoomId(Objects.nonNull(contractRefRoom.getRoomId())?contractRefRoom.getRoomId().toString():"");
        extendDto.setContractId(null);
        extendDto.setContractNo(contractHouseOwner.getContractNo());
        extendDto.setOwnerContractId(contractHouseOwner.getId());
        extendDto.setRoomName(contractRefRoom.getRoomName());
        extendDto.setApartmentId(contractRefRoom.getApartmentId());
        extendDto.setApartmentName(null);
        extendDto.setCustomName(contractHouseOwner.getOwnerName());
        extendDto.setCustomPhone(contractHouseOwner.getPhone());
        bpmProcessInstanceCreateReqDTO.setExtendDto(extendDto);
        CommonResult<String> processInstance =
                bpmProcessInstanceApi.createProcessInstance(getLoginUserId(),
                        bpmProcessInstanceCreateReqDTO);
        log.info("processInstance:{}", JsonUtils.toJsonString(processInstance));
        return processInstance.getCheckedData();

    }

    /**
     * 判断当前房间房态
     */
    private void validateRoomStatus(Long contractId) {
        // 查询业主合同关联的房间
        ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(contractId);
        if (Objects.isNull(contractRefRoom)) {
            throw exception(HOUSE_OWNER_CONTRACT_REF_ROOM_NOT_FOUND);
        }
        Long roomId = contractRefRoom.getRoomId();
        // 查询房态
        CommonResult<GetCurrentRecordRespVO> currentRecord = roomStateRecordApi.getCurrentRecord(roomId);
        log.info("业主合同退租，查询房态接口请求参数：{}，返回参数：{}", roomId, currentRecord);
        if (Objects.nonNull(currentRecord) && Objects.nonNull(currentRecord.getData())){
            // 判断房态  空房、冻结、维修  无锁可以退租
            RoomStateDTO roomState = ContractHouseOwnerConvert.INSTANCE.convertGetCurrectRecordResp2RoomState(currentRecord.getData());
            List<String> allowEvictionStates = Arrays.asList(RentStatusEnum.EMPTY.getValue(), RentStatusEnum.FREEZE.getValue(), RentStatusEnum.MAINTENANCE.getValue());
            if (!allowEvictionStates.contains(roomState.getState()) || roomState.getIsLock()){
                throw exception(ROOM_STATUS_NOT_ALLOW_EVICTION);
            }
        }

    }

    /**
     * 退租账单数据校验
     */
    private void validateOwnerEvictionReq(ContractHouseOwnerCancelReqVO reqVo, ContractHouseOwnerDO contractHouseOwner){
        BigDecimal deposit = contractHouseOwner.getDeposit();
        // 押金处理方式及金额校验
        BigDecimal depositHandleAmount = reqVo.getDepositHandleAmount();
        if (Objects.isNull(depositHandleAmount) || depositHandleAmount.compareTo(BigDecimal.ZERO) < 0 || depositHandleAmount.compareTo(deposit) > 0){
            throw exception(OWNER_CONTRACT_EVICTION_HANDLE_DEPOSIT_ERROR);
        }
        if (reqVo.getDepositHandleType().intValue() == ContractOwnerEvictionHandleTypeEnum.NOT_RETREAT.getCode().intValue()
                && depositHandleAmount.compareTo(BigDecimal.ZERO) != 0){
            throw exception(OWNER_CONTRACT_EVICTION_HANDLE_DEPOSIT_ERROR);
        }
    }

    /**
     * 退租账单处理
     */
    private void buildEvictionOrder(ContractHouseOwnerCancelReqVO reqVo, ContractHouseOwnerDO contractHouseOwner, ContractHouseOwnerRoomRefDO ownerRoomRef){
        // 数据校验
        validateOwnerEvictionReq(reqVo, contractHouseOwner);
        // 业主合同退租账单处理
        ownerOrderService.ownerWithdrawal(reqVo, ownerRoomRef);
    }


    @Override
    public void evictionApprovePass(Long id) {
        //退租审批通过
        //校验存在
        validateHouseOwnerExists(id);
        ContractHouseOwnerRoomRefDO ownerRoomRef = validateOwnerRefRoom(id);
        //修改合同状态
        LambdaUpdateWrapper<ContractHouseOwnerDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ContractHouseOwnerDO::getId, id);
        updateWrapper.set(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.NORMAL_END.getCode());
        updateWrapper.set(ContractHouseOwnerDO::getContractNode, ContractNodeEnum.RENTING_OUT.getCode());
        houseOwnerMapper.update(null, updateWrapper);
        // 修改房态为冻结
        FreezeRepairReqVO req = new FreezeRepairReqVO();
        req.setRoomHouseId(ownerRoomRef.getRoomId());
        roomHouseApi.roomFreeze(req);
    }


    @Override
    public void cancelContract(Long id) {
        // 校验存在
        ContractHouseOwnerDO contractHouseOwner = validateHouseOwnerExists(id);
//        if (!StringUtils.equals(contractHouseOwner.getContractNode(), ContractNodeEnum.RENEWAL.getCode())){
//            throw exception(ONLY_CANCEL_NOT_ACTIVE_OWNER_RENEWAL_CONTRACT);
//        }
        // 可取消状态  签约状态：非已签约  合同状态：待签约、待生效、审批驳回
        List<String> statusList = Arrays.asList(ContractOwnerStatusEnum.NO_SIGNED.getCode(), ContractOwnerStatusEnum.WAITING_ACTIVE.getCode(),ContractOwnerStatusEnum.REJECT.getCode());
        if (ContractSignStatusEnum.SIGNED.getCode().equals(contractHouseOwner.getSignStatus()) || !(statusList.contains(contractHouseOwner.getContractStatus()))){
            throw exception(OWNER_RENEWAL_CONTRACT_STATUS_UNABLE_CANCEL);
        }

//        // 判断业主账单是否已支付
//        if (ownerOrderService.checkOwnerOrderPaid(id, ONE)){
//            throw exception(OWNER_RENEWAL_CONTRACT_ORDER_PAID);
//        }

        // 取消业主合同
        // 合同状态改为已取消
        LambdaUpdateWrapper<ContractHouseOwnerDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ContractHouseOwnerDO::getId, id);
        updateWrapper.set(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.CANCELED.getCode());
        houseOwnerMapper.update(null, updateWrapper);

        // 删除业主账单
        ownerOrderService.deleteOrderByBusinessId(id, OrderTypeEnum.OWNER.getCode());

    }

    @Override
    public List<ContractHouseOwnerDO> getRenewalOwnerContractByContractId(Long contractId) {
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerDO::getRootId, contractId);
        queryWrapper.ne(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.CANCELED.getCode());
        queryWrapper.orderByDesc(ContractHouseOwnerDO::getCreateTime);
        return houseOwnerMapper.selectList(queryWrapper);
    }

    @Override
    public void changeRenewalContractStatus(LocalDate date) {
        if (Objects.isNull(date)){
            throw exception(UPDATE_RENEWAL_OWNER_CONTRACT_MISS_PARAM);
        }
        // 查询本次需要修改状态的业主续租合同
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.le(ContractHouseOwnerDO::getStartTime, date);
        queryWrapper.eq(ContractHouseOwnerDO::getContractNode, ContractNodeEnum.RENEWAL.getCode());
        queryWrapper.eq(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.WAITING_ACTIVE.getCode());
        List<ContractHouseOwnerDO> renewalHouseOwnerList = houseOwnerMapper.selectList(queryWrapper);
        log.info("查询到需要修改状态的业主续租合同，{}", JSONObject.toJSONString(renewalHouseOwnerList));
        if (CollectionUtils.isNotEmpty(renewalHouseOwnerList)){
            for (ContractHouseOwnerDO renewalHouseOwner : renewalHouseOwnerList) {
                ContractHouseOwnerDO originalHouseOwner = houseOwnerMapper.selectById(renewalHouseOwner.getOriginalContractId());
                // 原合同状态正常结束
                originalHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
//                // 续租合同押金结转
//                ownerOrderService.handleRenewalOrder(originalHouseOwner.getId());
                // 更新原合同
                houseOwnerMapper.updateById(originalHouseOwner);
                // 续租合同状态已生效
                renewalHouseOwner.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
                // 更新续租合同
                houseOwnerMapper.updateById(renewalHouseOwner);
            }
        }
    }


    @Override
    public PageResult<ContractHouseOwnerPageRespVO> getHouseOwnerHomePage(HomeQueryVO queryDTO) {
        Page<ContractHouseOwnerDO> page = new Page<>(queryDTO.getPageNo(),queryDTO.getPageSize());
        queryDTO.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
        IPage<ContractHouseOwnerDO> pageQueryList = houseOwnerMapper.pageContractOwnerHomeList(page, queryDTO);
        if (CollectionUtils.isEmpty(pageQueryList.getRecords())){
            return new PageResult<>(new ArrayList<>(), page.getTotal());
        }
        List<ContractHouseOwnerPageRespVO> pageList = ContractHouseOwnerConvert.INSTANCE.convertList(page.getRecords());
        for (ContractHouseOwnerPageRespVO ownerPageRespVO : pageList) {
            // 房间名称处理
            List<ContractHouseOwnerRoomRefDO> roomRefDOList = contractHouseOwnerRoomRefMapper.selectList(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId, ownerPageRespVO.getId());
            if (CollectionUtils.isNotEmpty(roomRefDOList)){
                ContractHouseOwnerRoomRefDO houseOwnerRoomRefDO = roomRefDOList.get(ZERO);
                ownerPageRespVO.setRoomName(houseOwnerRoomRefDO.getApartmentName() + houseOwnerRoomRefDO.getRoomName());
            }
            // 状态处理
            long differDays = queryDTO.getStartDate().toEpochDay() - ownerPageRespVO.getEndTime().toEpochDay();
            if (0L == differDays){
                ownerPageRespVO.setStatusStr("应处理");
            }else {
                ownerPageRespVO.setStatusStr(String.format("已逾期%s天", differDays));
            }
        }

        return new PageResult<>(pageList, page.getTotal());
    }

    @Override
    public Integer countHouseOwnerHomePage(HomeQueryVO queryDTO) {
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.le(ContractHouseOwnerDO::getEndTime, queryDTO.getStartDate());
        queryWrapper.eq(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.ACTIVE.getCode());
        return houseOwnerMapper.selectCount(queryWrapper).intValue();
    }

    @Override
    public void updateContractStatus(ApproveReqVO approveReqVO) {
        ContractHouseOwnerDO contractHouseOwnerDO = houseOwnerMapper.selectById(approveReqVO.getId());
        if (Objects.nonNull(contractHouseOwnerDO)){
            if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(approveReqVO.getResult())) {
                String contractStatus = ContractOwnerStatusEnum.ACTIVE.getCode();
                // 签约状态非已签约  电子合同
                if (!ContractSignStatusEnum.SIGNED.getCode().equals(contractHouseOwnerDO.getSignStatus())){
                    contractStatus = ContractOwnerStatusEnum.NO_SIGNED.getCode();
                }
                // 未到开始时间  待生效
                if (ContractNodeEnum.RENEWAL.getCode().equals(contractHouseOwnerDO.getContractNode())
                        && ContractTypeEnum.PAPER.getCode().equals(contractHouseOwnerDO.getContractType())
                        && contractHouseOwnerDO.getStartTime().isAfter(LocalDate.now())){
                    contractStatus = ContractOwnerStatusEnum.WAITING_ACTIVE.getCode();
                }
                houseOwnerMapper.updateById(ContractHouseOwnerDO.builder()
                        .id(approveReqVO.getId())
                        .contractStatus(contractStatus)
                        .build());
                // 已生效 续租合同 原合同状态为结束
                if (ContractNodeEnum.RENEWAL.getCode().equals(contractHouseOwnerDO.getContractNode())
                        && ContractOwnerStatusEnum.ACTIVE.getCode().equals(contractStatus)
                        && Objects.nonNull(contractHouseOwnerDO.getOriginalContractId())){
                    // 续租合同 修改原合同状态
                    houseOwnerMapper.updateById(ContractHouseOwnerDO.builder()
                            .id(contractHouseOwnerDO.getOriginalContractId())
                            .contractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode())
                            .build());
                }
            } else {
                houseOwnerMapper.updateById(ContractHouseOwnerDO.builder()
                        .id(approveReqVO.getId())
                        .contractStatus(ContractOwnerStatusEnum.REJECT.getCode())
                        .build());
            }
        }
    }

    @Override
    public OwnerHouseRentInfoRespVO getAppRentInfo(Long memberNo) {
        OwnerHouseRentInfoRespVO rentInfoRespVO = new OwnerHouseRentInfoRespVO();
        if (Objects.isNull(memberNo)){
            return rentInfoRespVO;
        }
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerDO::getMemberId, memberNo);
        queryWrapper.eq(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.ACTIVE.getCode());
        List<ContractHouseOwnerDO> houseOwnerList = houseOwnerMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(houseOwnerList)){
            return rentInfoRespVO;
        }
        List<Long> houseOwnerIds = houseOwnerList.stream().map(ContractHouseOwnerDO::getId).collect(Collectors.toList());
        // 查询关联房源
        List<ContractHouseOwnerRoomRefDO> roomRefList = contractHouseOwnerRoomRefMapper.selectList(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId, houseOwnerIds);
        // roomId分组
        Map<Long, List<ContractHouseOwnerRoomRefDO>> roomRefMap = roomRefList.stream().collect(Collectors.groupingBy(ContractHouseOwnerRoomRefDO::getRoomId));
        // 出租数
        rentInfoRespVO.setLeaseNum(roomRefMap.size());
        // 已收租金金额
        BigDecimal receivedRent = BigDecimal.ZERO;
        // 总租金
        BigDecimal totalRent = BigDecimal.ZERO;

        for (ContractHouseOwnerDO contractHouseOwnerDO : houseOwnerList) {
            RentOrderQueryDTO param = new RentOrderQueryDTO();
            param.setBusinessId(contractHouseOwnerDO.getId());
            param.setOrderType(OrderTypeEnum.OWNER.getCode());
            List<RentOrderDO> listByParam = ownerOrderService.getListByParam(param);
            if (CollectionUtils.isNotEmpty(listByParam)){
                for (RentOrderDO rentOrderDO : listByParam) {
                    receivedRent = receivedRent.add(rentOrderDO.getPaidRentUtilities());
                    totalRent = totalRent.add(rentOrderDO.getTotalAmount());
                }
            }
        }
        BigDecimal subtract = totalRent.subtract(receivedRent);
        // 待收租金金额
        BigDecimal notReceivedRent = subtract.compareTo(BigDecimal.ZERO) >= 0 ? subtract : BigDecimal.ZERO;
        rentInfoRespVO.setReceivedRent(receivedRent);
        rentInfoRespVO.setNotReceivedRent(notReceivedRent);
        return rentInfoRespVO;
    }


    @Override
    public PageResult<OwnerHouseInfoRespVO> pageAppOwnerRoomInfo(OwnerHouseRoomQueryReqVO param) {
        Page<ContractHouseOwnerDO> page = new Page<>(param.getPageNo(),param.getPageSize());
        LocalDate nowDate =  LocalDate.now();
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractHouseOwnerDO::getContractStatus, ContractOwnerStatusEnum.ACTIVE.getCode());
        queryWrapper.eq(ContractHouseOwnerDO::getMemberId, param.getMemberId());
//        queryWrapper.le(ContractHouseOwnerDO::getStartTime, nowDate);
//        queryWrapper.ge(ContractHouseOwnerDO::getEndTime, nowDate);
        page = houseOwnerMapper.selectPage(page, queryWrapper);
        if (Objects.isNull(page)){
            return null;
        }
        List<ContractHouseOwnerDO> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)){
            return null;
        }
        // 查询关联房源
        List<Long> contractIds = records.stream().map(ContractHouseOwnerDO::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(contractIds)){
            return null;
        }
        List<ContractHouseOwnerRoomRefDO> roomRefList = contractHouseOwnerRoomRefMapper.selectList(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId, contractIds);
        if (CollectionUtils.isEmpty(roomRefList)){
            return null;
        }
        // 合同-房源Map
        Map<Long, Long> contractRoomMap = roomRefList.stream().filter(o -> Objects.nonNull(o.getContractHouseOwnerId()))
                .distinct().collect(Collectors.toMap(ContractHouseOwnerRoomRefDO::getContractHouseOwnerId,ContractHouseOwnerRoomRefDO::getRoomId));
        // 查询房源信息
        List<Long> roomIds = roomRefList.stream().map(ContractHouseOwnerRoomRefDO::getRoomId).distinct().collect(Collectors.toList());
        CommonResult<List<RoomHouseRespVo>> roomHouseByIds = roomHouseApi.getRoomHouseByIds(roomIds);
        log.info("查询房源信息，请求参数：{}，返回参数：{}", roomIds, Objects.nonNull(roomHouseByIds) ? JSONObject.toJSONString(roomHouseByIds) : "");
        // 房源Id-房间名称Map
        Map<Long, String> roomNameMap = roomHouseByIds.getData().stream().filter(o -> StringUtils.isNotBlank(o.getFullRoomName()))
                .distinct().collect(Collectors.toMap(RoomHouseRespVo::getId,RoomHouseRespVo::getFullRoomName));
        List<OwnerHouseInfoRespVO> respList = new ArrayList<>();
        for (ContractHouseOwnerDO record : records) {
            OwnerHouseInfoRespVO respVO = new OwnerHouseInfoRespVO();
            if (!contractRoomMap.containsKey(record.getId())){
                continue;
            }
            if (!roomNameMap.containsKey(contractRoomMap.get(record.getId()))){
                continue;
            }
            Long roomId = contractRoomMap.get(record.getId());
            respVO.setRoomName(roomNameMap.get(contractRoomMap.get(record.getId())));
            respVO.setOwnerContractId(record.getId());
            respVO.setRoomId(roomId);
            respVO.setStartTime(record.getStartTime());
            respVO.setEndTime(record.getEndTime());
            // 查询业主账单
            RentOrderQueryDTO orderParam = new RentOrderQueryDTO();
            orderParam.setBusinessId(record.getId());
            orderParam.setOrderType(OrderTypeEnum.OWNER.getCode());
            List<RentOrderDO> listByParam = ownerOrderService.getListByParam(orderParam);
            if (CollectionUtils.isNotEmpty(listByParam)){
                listByParam.sort(Comparator.comparing(RentOrderDO::getOughtPayTime));
                // 排序后 最后一个账单的期数为总周期数
                RentOrderDO lastRentOrder = listByParam.get(listByParam.size() - 1);
                respVO.setOrderPeriods(lastRentOrder.getNum());
                for (RentOrderDO rentOrderDO : listByParam) {
                    // 排序后 第一个待支付 部分支付的账单即为下次收款日期
                    List<String> payStatusList = Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(), OrderPayStatusEnum.PART.getCode());
                    if (payStatusList.contains(rentOrderDO.getPayStatus())){
                        respVO.setNextCollectionDate(rentOrderDO.getOughtPayTime());
                        break;
                    }
                }
            }

            // 查询房间当前合同
            RoomContractRespVO roomContract = contractRoomService.getRoomContract(roomId);
            if (Objects.isNull(roomContract) || !ContractStatusEnum.CHECK_IN.getCode().equals(roomContract.getContractStatus())){
                respVO.setLiveStatus("未入住");
                respVO.setCurrentLiveNum(ZERO);
                respList.add(respVO);
                continue;
            }
            respVO.setLiveStatus("已入住");
            ContractRoommateDO roommateParam = new ContractRoommateDO();
            roommateParam.setStatus("2");
            roommateParam.setRoomContractId(roomContract.getId());
            List<ContractRoommateDO> byParam = contractRoommateService.getByParam(roommateParam);
            respVO.setCurrentLiveNum(ONE);
            if (CollectionUtils.isNotEmpty(byParam)){
                respVO.setCurrentLiveNum(byParam.size());
            }
            respList.add(respVO);
        }
        return new PageResult<>(respList, page.getTotal());
    }

    @Override
    public void updateOwner(ContractHouseOwnerDO houseOwnerDO) {
        if (Objects.isNull(houseOwnerDO) || Objects.isNull(houseOwnerDO.getId())){
            return;
        }
        houseOwnerMapper.updateById(houseOwnerDO);
    }

    @Override
    public List<ContractHouseOwnerDO> getByParam(ContractHouseOwnerQueryDTO param) {
        if (Objects.isNull(param)){
            return null;
        }
        LambdaQueryWrapper<ContractHouseOwnerDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(param.getContractStatus()),ContractHouseOwnerDO::getContractStatus,param.getContractStatus());
        queryWrapper.in(CollectionUtils.isNotEmpty(param.getContractStatusList()),ContractHouseOwnerDO::getContractStatus,param.getContractStatusList());
        queryWrapper.eq(StringUtils.isNotBlank(param.getApproveStatus()),ContractHouseOwnerDO::getApproveStatus,param.getApproveStatus());
        queryWrapper.in(CollectionUtils.isNotEmpty(param.getApproveStatusList()),ContractHouseOwnerDO::getApproveStatus,param.getApproveStatusList());
        queryWrapper.eq(StringUtils.isNotBlank(param.getSignStatus()),ContractHouseOwnerDO::getSignStatus,param.getSignStatus());
        queryWrapper.eq(StringUtils.isNotBlank(param.getContractType()),ContractHouseOwnerDO::getContractType,param.getContractType());
        queryWrapper.eq(Objects.nonNull(param.getMemberId()),ContractHouseOwnerDO::getMemberId,param.getMemberId());
        queryWrapper.le(Objects.nonNull(param.getLeLessorSignTime()), ContractHouseOwnerDO::getLessorSignTime, param.getLeLessorSignTime());
        queryWrapper.orderByDesc(ContractHouseOwnerDO::getCreateTime);
        return houseOwnerMapper.selectList(queryWrapper);
    }

    @Override
    public void callbackSignSuccess(Long ownerContractId) {
        // 电子合同签约完成回调
        ContractHouseOwnerDO contractHouseOwnerDO = validateHouseOwnerExists(ownerContractId);
        ContractHouseOwnerDO updateReq = new ContractHouseOwnerDO();
        updateReq.setId(ownerContractId);
        updateReq.setSignStatus(ContractSignStatusEnum.SIGNED.getCode());
        updateReq.setContractStatus(ContractOwnerStatusEnum.ACTIVE.getCode());
        // 续租合同
        if (ContractNodeEnum.RENEWAL.getCode().equals(contractHouseOwnerDO.getContractNode())){
            LocalDate nowDate = LocalDate.now();
            // 合同未开始 待生效
            if (contractHouseOwnerDO.getStartTime().isAfter(nowDate)){
                updateReq.setContractStatus(ContractOwnerStatusEnum.WAITING_ACTIVE.getCode());
            }else {
                // 已生效续租合同 修改原合同为已结束
                ContractHouseOwnerDO originalHouseOwner = new ContractHouseOwnerDO();
                originalHouseOwner.setId(contractHouseOwnerDO.getOriginalContractId());
                originalHouseOwner.setContractStatus(ContractOwnerStatusEnum.NORMAL_END.getCode());
                // 更新原合同
                houseOwnerMapper.updateById(originalHouseOwner);
            }
        }
        this.updateOwner(updateReq);
    }

    @Override
    public void updateMemberUser(Long userId, String mobile, String userName, Long oldUserId) {
        houseOwnerMapper.updateMemberUser(userId,mobile,userName,oldUserId);
    }


    @Override
    public List<OwnerContractRoomDTO> getOwnerOrderByRoomIds(List<Long> roomIds) {
        if (CollectionUtils.isNotEmpty(roomIds)){
            return houseOwnerMapper.getOwnerContractByRoomIds(roomIds);
        }
        return null;
    }


    @Override
    public Boolean checkRenewal(Long id) {
        // 所有账单都支付才可以续租
        RentOrderQueryDTO param = new RentOrderQueryDTO();
        param.setBusinessId(id);
        param.setOrderType(OrderTypeEnum.OWNER.getCode());
        param.setPayStatusList(Arrays.asList(OrderPayStatusEnum.UNPAID.getCode(),OrderPayStatusEnum.PART.getCode()));
        List<RentOrderDO> listByParam = ownerOrderService.getListByParam(param);
        if (CollectionUtils.isNotEmpty(listByParam)){
            throw exception(EXIST_UNPAID_OWNER_ORDER);
        }
        return true;
    }

    @Override
    public void updateHouseOwnerCard(ContractHouseOwnerCardUpdateReqVO updateReqVO) {
        // 校验存在
        ContractHouseOwnerDO contractHouseOwnerDO = validateHouseOwnerExists(updateReqVO.getId());
        List<String> ownerStatusList = Arrays.asList(ContractOwnerStatusEnum.NO_SIGNED.getCode(), ContractOwnerStatusEnum.WAITING_ACTIVE.getCode(),
                ContractOwnerStatusEnum.ACTIVE.getCode(), ContractOwnerStatusEnum.REJECT.getCode());
        if (!ownerStatusList.contains(contractHouseOwnerDO.getContractStatus())){
            throw exception(OWNER_STATUS_UNABLE_TO_OPERATE);
        }
        // 更新
        ContractHouseOwnerDO updateObj = new ContractHouseOwnerDO();
        updateObj.setCardholder(updateReqVO.getCardholder());
        updateObj.setCreditCard(updateReqVO.getCreditCard());
        updateObj.setBank(updateReqVO.getBank());
        updateObj.setBankCode(updateReqVO.getBankCode());
        updateObj.setBankCity(updateReqVO.getBankCity());
        updateObj.setBankProvince(updateReqVO.getBankProvince());
        updateObj.setBranchBank(updateReqVO.getBranchBank());
        updateObj.setId(updateReqVO.getId());
        houseOwnerMapper.updateById(updateObj);
    }

    @Override
    public List<ContractHouseOwnerPropertyTemplateDO> ownerPropertyTemplateList(Long apartmentId) {
        if (Objects.nonNull(apartmentId)){
            List<ContractHouseOwnerPropertyTemplateDO> templateDOS = ownerPropertyTemplateMapper.selectList(ContractHouseOwnerPropertyTemplateDO::getApartmentId, apartmentId);
            if (CollectionUtils.isNotEmpty(templateDOS)){
                return templateDOS;
            }
        }
        // 默认数据
        return TenantUtils.executeIgnoreAndReturn(() -> {
            LambdaQueryWrapper<ContractHouseOwnerPropertyTemplateDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.isNull(ContractHouseOwnerPropertyTemplateDO::getTenantId);
            queryWrapper.isNull(ContractHouseOwnerPropertyTemplateDO::getApartmentId);
            return ownerPropertyTemplateMapper.selectList(queryWrapper);
        });
    }


    @Override
    public ContractHouseOwnerRespVO getHouseOwnerWithRefRoom(Long id) {
        ContractHouseOwnerDO contractHouseOwner = houseOwnerMapper.selectById(id);
        ContractHouseOwnerRespVO resp = ContractHouseOwnerConvert.INSTANCE.convert(contractHouseOwner);
        if (Objects.nonNull(contractHouseOwner)){
            //查询关联房间信息
            ContractHouseOwnerRoomRefDO contractRefRoom = getContractRefRoom(id);
            if (Objects.nonNull(contractRefRoom)){
                resp.setRefRoom(ContractHouseOwnerRoomRefConvert.INSTANCE.convertRoomRefDO2RoomRefVO(contractRefRoom));
            }
        }
        return resp;
    }

    @Override
    public Boolean changeHousekeep(ChangeHousekeepReqVO reqVO) {
        LambdaUpdateWrapper<ContractHouseOwnerDO> update = Wrappers.lambdaUpdate();
        update.set(ContractHouseOwnerDO::getButlerId,reqVO.getButlerId())
                .set(ContractHouseOwnerDO::getButlerName,reqVO.getButlerName())
                .in(ContractHouseOwnerDO::getId,reqVO.getIds());
        return houseOwnerMapper.update(null,update)>0;
    }
}

